home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-13 / tde3.zip / UTILS.C < prev    next >
C/C++ Source or Header  |  1993-06-05  |  79KB  |  2,812 lines

  1. /*******************  start of original comments  ********************/
  2. /*
  3.  * Written by Douglas Thomson (1989/1990)
  4.  *
  5.  * This source code is released into the public domain.
  6.  */
  7.  
  8. /*
  9.  * Name:    dte - Doug's Text Editor program - miscellaneous utilities
  10.  * Purpose: This file contains miscellaneous functions that were required
  11.  *           in more than one of the other files, or were thought to be
  12.  *           likely to be used elsewhere in the future.
  13.  * File:    utils.c
  14.  * Author:  Douglas Thomson
  15.  * System:  this file is intended to be system-independent
  16.  * Date:    October 1, 1989
  17.  */
  18. /*********************  end of original comments  ********************/
  19.  
  20.  
  21. /*
  22.  * The utility routines have been EXTENSIVELY rewritten.  Update screens as
  23.  * needed.  Most times, only one line has changed.  Just show changed line
  24.  * in all windows if it is on screen.
  25.  *
  26.  * Support routines for text lines longer than screen width have been added.
  27.  * Currently support lines as long as 1040 characters.
  28.  *
  29.  * In DTE, Doug chose to test whether characters are part of a word.  In TDE,
  30.  * we will test whether characters are not part of a word.  The character
  31.  * set not part of a word will not change as much as the characters that
  32.  * are part of a word.  In most languages, human and computer, the delimiters
  33.  * are much more common across languages than the tokens that make up a word.
  34.  * Thanks to Pierre Jelenc, pcj1@columbia.edu, for recommending looking for
  35.  * delimiters.
  36.  *
  37.  * New editor name:  TDE, the Thomson-Davis Editor.
  38.  * Author:           Frank Davis
  39.  * Date:             June 5, 1991, version 1.0
  40.  * Date:             July 29, 1991, version 1.1
  41.  * Date:             October 5, 1991, version 1.2
  42.  * Date:             January 20, 1992, version 1.3
  43.  * Date:             February 17, 1992, version 1.4
  44.  * Date:             April 1, 1992, version 1.5
  45.  * Date:             June 5, 1992, version 2.0
  46.  * Date:             October 31, 1992, version 2.1
  47.  * Date:             April 1, 1993, version 2.2
  48.  * Date:             June 5, 1993, version 3.0
  49.  *
  50.  * This modification of Douglas Thomson's code is released into the
  51.  * public domain, Frank Davis.  You may distribute it freely.
  52.  */
  53.  
  54. #include "tdestr.h"
  55. #include "common.h"
  56. #include "define.h"
  57. #include "tdefunc.h"
  58.  
  59.  
  60. /*
  61.  * Name:    myiswhitespc
  62.  * Purpose: To determine whether or not a character is *NOT* part of a "word".
  63.  * Date:    July 4, 1992
  64.  * Passed:  c: the character to be tested
  65.  * Returns: TRUE if c is in the character set *NOT* part of a word
  66.  * Notes:   The characters in the set not part of a word will not change as
  67.  *           as much as the characters that are part of a word.  In most
  68.  *           languages, human and computer, the delimiters are much more
  69.  *           common than the tokens that make up a word.  For example,
  70.  *           the set of punction characters don't change as much across
  71.  *           languages, human and computer, as the characters that make
  72.  *           up the alphabet, usually.  In other words, the delimiters
  73.  *           are fairly constant across languages.
  74.  */
  75. int  myiswhitespc( int c )
  76. {
  77.    return( c == ' ' || (ispunct( c ) && c != '_') || iscntrl( c ) );
  78. }
  79.  
  80.  
  81. /*
  82.  * Name:    check_virtual_col
  83.  * Purpose: ensure integrity of rcol, ccol, and bcol
  84.  * Date:    June 5, 1991
  85.  * Passed:  window:  pointer to current window
  86.  *          rcol: real column of cursor
  87.  *          ccol: current or logical column of cursor
  88.  */
  89. void check_virtual_col( WINDOW *window, int rcol, int ccol )
  90. {
  91. register int bcol;
  92. int  start_col;
  93. int  end_col;
  94. file_infos *file;
  95.  
  96.    file      = window->file_info;
  97.    bcol      = window->bcol;
  98.    start_col = window->start_col;
  99.    end_col   = window->end_col;
  100.  
  101.    /*
  102.     * is logical column past end of screen?
  103.     */
  104.    if (ccol > end_col) {
  105. /*      ccol = start_col + (end_col + 1 - start_col) / 2;  */
  106.       ccol = end_col;
  107.       bcol = rcol - (ccol - start_col);
  108.       file->dirty = LOCAL;
  109.    }
  110.  
  111.    /*
  112.     * is logical column behind start of screen?
  113.     */
  114.    if (ccol < start_col) {
  115.       if (bcol >= (start_col - ccol))
  116.          bcol -= (start_col - ccol);
  117.       ccol = start_col;
  118.       file->dirty = LOCAL;
  119.    }
  120.  
  121.    /*
  122.     * is real column < base column?
  123.     */
  124.    if (rcol < bcol) {
  125.       ccol = rcol + start_col;
  126.       bcol = 0;
  127.       if (ccol > end_col) {
  128.          bcol = rcol;
  129.          ccol = start_col;
  130.       }
  131.       file->dirty = LOCAL;
  132.    }
  133.  
  134.    /*
  135.     * current column + base column MUST equal real column
  136.     */
  137.    if ((ccol - start_col) + bcol != rcol) {
  138.       if (bcol < 0 || bcol > rcol) {
  139.          bcol = rcol;
  140.          file->dirty = LOCAL;
  141.       }
  142.       ccol = rcol - bcol + start_col;
  143.       if (ccol > end_col) {
  144.          bcol = rcol;
  145.          ccol = start_col;
  146.          file->dirty = LOCAL;
  147.       }
  148.    }
  149.  
  150.    /*
  151.     * rcol CANNOT be negative
  152.     */
  153.    if (rcol < 0) {
  154.       rcol = bcol = 0;
  155.       ccol = start_col;
  156.       file->dirty = LOCAL;
  157.    }
  158.  
  159.    if (rcol >= MAX_LINE_LENGTH) {
  160.       rcol = MAX_LINE_LENGTH - 1;
  161.       bcol = rcol - (ccol - start_col);
  162.    }
  163.  
  164.    assert( rcol >= 0 );
  165.    assert( rcol < MAX_LINE_LENGTH );
  166.    assert( bcol >= 0 );
  167.    assert( bcol < MAX_LINE_LENGTH );
  168.    assert( ccol >= start_col );
  169.    assert( ccol <= end_col );
  170.  
  171.    window->bcol = bcol;
  172.    window->ccol = ccol;
  173.    window->rcol = rcol;
  174. }
  175.  
  176.  
  177. /*
  178.  * Name:    copy_line
  179.  * Purpose: To copy the cursor line, if necessary, into the current line
  180.  *           buffer, so that changes can be made efficiently.
  181.  * Date:    June 5, 1991
  182.  * Passed:  text_line: line to be copied to line buffer
  183.  *          line: line to display error message
  184.  * Notes:   See un_copy_line, the reverse operation.
  185.  *          DO NOT use the C library string functions on text in
  186.  *           g_status.line_buff, because Null characters are allowed as
  187.  *           normal text in the file.
  188.  */
  189. void copy_line( line_list_ptr ll )
  190. {
  191. register unsigned int len;
  192. text_ptr text_line;
  193.  
  194.    if (g_status.copied == FALSE  &&  ll->len != EOF) {
  195.  
  196.       assert( ll != NULL );
  197.  
  198.       len = ll->len;
  199.       text_line = ll->line;
  200.       g_status.buff_node = ll;
  201.  
  202.       assert( len < MAX_LINE_LENGTH );
  203.  
  204.       if (text_line != NULL)
  205.          _fmemcpy( g_status.line_buff, text_line, len );
  206.  
  207.       g_status.line_buff_len = len;
  208.       g_status.copied = TRUE;
  209.    }
  210. }
  211.  
  212.  
  213. /*
  214.  * Name:    un_copy_line
  215.  * Purpose: To copy the cursor line, if necessary, from the current line
  216.  *           buffer, shifting the main text to make the right amount of
  217.  *           room.
  218.  * Date:    June 5, 1991
  219.  * Passed:  test_line:  location in file to copy line buffer
  220.  *          window:  pointer to current window
  221.  *          del_trailing:  delete the trailing blanks at eol? TRUE or FALSE
  222.  * Notes:   For some functions, trailing spaces should not be removed when
  223.  *           returning the line buffer to the main text.  The JoinLine function
  224.  *           is a good example.  We need to leave trailing space so when we
  225.  *           join lines - the current line will extend at least up to
  226.  *           the column of the cursor.  We need to leave trailing space
  227.  *           during BOX block operations.
  228.  *          See copy_line, the reverse operation.
  229.  */
  230. int  un_copy_line( line_list_ptr ll, WINDOW *window, int del_trailing )
  231. {
  232. text_ptr p;
  233. size_t len;     /* length of line buffer text */
  234. size_t ll_len;  /* length of ll->line */
  235. int  net_change;
  236. int  rc;
  237. char c;
  238. file_infos *file;
  239. WINDOW *wp;
  240.  
  241.    rc = OK;
  242.    if (mode.do_backups == TRUE)
  243.       rc = backup_file( window );
  244.  
  245.    if (g_status.copied == TRUE  &&  ll->len != EOF) {
  246.  
  247.       file = window->file_info;
  248.  
  249.       /*
  250.        * if we are deleting the entire line, don't worry about the
  251.        *  deleting the trailing space, since we're deleting entire line.
  252.        */
  253.       if (g_status.command == DeleteLine)
  254.          del_trailing = FALSE;
  255.  
  256.       if (del_trailing  &&  mode.trailing  &&  file->crlf != BINARY) {
  257.          len = g_status.line_buff_len;
  258.          for (p=(text_ptr)(g_status.line_buff+len); len > 0; len--, p--) {
  259.             c = *(p - 1);
  260.             if (c != ' '  &&  c != '\t')
  261.                break;
  262.             if (!mode.inflate_tabs && c == '\t')
  263.                break;
  264.          }
  265.          g_status.line_buff_len = len;
  266.          file->dirty = GLOBAL;
  267.          if (window->visible == TRUE)
  268.             show_changed_line( window );
  269.       }
  270.       len = g_status.line_buff_len;
  271.       ll_len =  (ll->line == NULL) ? 0 : ll->len;
  272.  
  273.  
  274.       assert( len < MAX_LINE_LENGTH );
  275.       assert( ll_len < MAX_LINE_LENGTH );
  276.  
  277.       net_change = len - ll_len;
  278.  
  279.       if (ll_len != len  ||  ll->line == NULL) {
  280.          /*
  281.           * let malloc space for the new line before we free the old line.
  282.           */
  283.          p = my_malloc( len, &rc );
  284.          if (rc == ERROR)
  285.             error( WARNING, window->bottom_line, main4 );
  286.  
  287.          /*
  288.           * free the space taken up by current line in far heap.
  289.           */
  290.          if (rc != ERROR  &&  ll->line != NULL)
  291.             my_free( ll->line );
  292.       } else
  293.          p = ll->line;
  294.  
  295.       if (rc != ERROR) {
  296.          if (len > 0)
  297.             _fmemcpy( p, g_status.line_buff, len );
  298.          ll->line = p;
  299.          ll->len = len;
  300.  
  301.          if (net_change != 0) {
  302.             for (wp=g_status.window_list; wp != NULL; wp=wp->next) {
  303.                if (wp->file_info == file && wp != window)
  304.                   if (wp->rline > window->rline)
  305.                      wp->bin_offset += net_change;
  306.             }
  307.          }
  308.  
  309.          file->modified = TRUE;
  310.          show_avail_mem( );
  311.       }
  312.    }
  313.    g_status.copied = FALSE;
  314.    return( rc );
  315. }
  316.  
  317.  
  318. /*
  319.  * Name:    un_copy_tab_buffer
  320.  * Purpose: To copy the tab buffer line the main text buffer
  321.  * Date:    October 31, 1992
  322.  * Passed:  line_number:  line number to copy line tab out buffer
  323.  *          window:       pointer to current window
  324.  */
  325. int  un_copy_tab_buffer( line_list_ptr ll, WINDOW *window )
  326. {
  327. text_ptr p;
  328. int  len;               /* length of current line buffer text */
  329. int  net_change;
  330. int  rc;
  331. file_infos *file;
  332. WINDOW *wp;
  333.  
  334.    rc = OK;
  335.    file = window->file_info;
  336.    /*
  337.     * file has changed.  lets create the back_up if needed
  338.     */
  339.    if (mode.do_backups == TRUE) {
  340.       window->file_info->modified = TRUE;
  341.       rc = backup_file( window );
  342.    }
  343.  
  344.    len = g_status.tabout_buff_len;
  345.  
  346.    assert( len >= 0 );
  347.    assert( len < MAX_LINE_LENGTH );
  348.    assert( ll->len >= 0 );
  349.    assert( ll->len < MAX_LINE_LENGTH );
  350.  
  351.    /*
  352.     * if the far heap has run out of space, then only part of the
  353.     *  current line can be moved back into the far heap. Warn the user
  354.     *  that some of the current line has been lost.
  355.     */
  356.    p = my_malloc( len, &rc );
  357.    if (rc == ERROR)
  358.       error( WARNING, window->bottom_line, main4 );
  359.  
  360.    if (rc == OK) {
  361.       net_change = len - ll->len;
  362.  
  363.       if (ll->line != NULL)
  364.          my_free( ll->line );
  365.       if (len > 0)
  366.          _fmemcpy( p, g_status.line_buff, len );
  367.       ll->line = p;
  368.       ll->len  = len;
  369.  
  370.       if (net_change != 0) {
  371.          for (wp=g_status.window_list; wp != NULL; wp=wp->next) {
  372.             if (wp->file_info == file && wp != window)
  373.                if (wp->rline > window->rline)
  374.                   wp->bin_offset += net_change;
  375.          }
  376.       }
  377.  
  378.       file->modified = TRUE;
  379.    }
  380.    return( rc );
  381. }
  382.  
  383.  
  384. /*
  385.  * Name:    load_undo_buffer
  386.  * Purpose: To copy the cursor line to the undo buffer.
  387.  * Date:    September 26, 1991
  388.  * Passed:  file:          pointer to file
  389.  *          line_to_undo:  pointer to line in file to save
  390.  * Notes:   save the last mode.undo_max lines in a stack.  when we overflow
  391.  *           the stack, dump the oldest line.
  392.  */
  393. void load_undo_buffer( file_infos *file, text_ptr line_to_undo, int len )
  394. {
  395. int  rc;
  396. text_ptr l;
  397. line_list_ptr temp_ll;
  398.  
  399.    rc = OK;
  400.    if (file->undo_count >= mode.undo_max) {
  401.       --file->undo_count;
  402.       temp_ll = file->undo_bot->prev;
  403.       temp_ll->prev->next = file->undo_bot;
  404.       file->undo_bot->prev = temp_ll->prev;
  405.       if (temp_ll->line != NULL)
  406.          my_free( temp_ll->line );
  407.    } else
  408.       temp_ll = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  409.  
  410.    assert( len >= 0 );
  411.    assert( len < MAX_LINE_LENGTH );
  412.  
  413.    l = my_malloc( len, &rc );
  414.  
  415.    if (rc == ERROR) {
  416.       if (l != NULL)
  417.          my_free( l );
  418.       if (temp_ll != NULL)
  419.          my_free( temp_ll );
  420.    } else {
  421.       if (len > 0)
  422.          _fmemcpy( l, line_to_undo, len );
  423.       temp_ll->line  = l;
  424.       temp_ll->len   = len;
  425.       temp_ll->dirty = TRUE;
  426.  
  427.       temp_ll->prev = NULL;
  428.       temp_ll->next = file->undo_top;
  429.       file->undo_top->prev = temp_ll;
  430.       file->undo_top = temp_ll;
  431.  
  432.       ++file->undo_count;
  433.    }
  434. }
  435.  
  436.  
  437. /*
  438.  * Name:    set_prompt
  439.  * Purpose: To display a prompt, highlighted, at the bottom of the screen.
  440.  * Date:    October 1, 1989
  441.  * Passed:  prompt: prompt to be displayed
  442.  *          line:   line to display prompt
  443.  */
  444. void set_prompt( char *prompt, int line )
  445. {
  446. register int prompt_col;
  447.  
  448.    /*
  449.     * work out where the answer should go
  450.     */
  451.    prompt_col = strlen( prompt );
  452.  
  453.    assert( prompt_col <= MAX_COLS );
  454.  
  455.    /*
  456.     * output the prompt
  457.     */
  458.    s_output( prompt, line, 0, g_display.message_color );
  459.    eol_clear( prompt_col, line, g_display.message_color );
  460.  
  461.    /*
  462.     * put cursor at end of prompt
  463.     */
  464.    xygoto( prompt_col, line );
  465. }
  466.  
  467.  
  468. /*
  469.  * Name:    get_name
  470.  * Purpose: To prompt the user and read the string entered in response.
  471.  * Date:    June 5, 1992
  472.  * Passed:  prompt: prompt to offer the user
  473.  *          line:   line to display prompt
  474.  *          name:   default answer
  475.  *          color:  color to display prompt
  476.  * Returns: name:   user's answer
  477.  *          OK if user entered something
  478.  *          ERROR if user aborted the command
  479.  * Notes:   with the addition of macros in tde, this function became a little
  480.  *           more complicated.  we have to deal with both executing macros
  481.  *           and macros that are the user uses when entering normal text
  482.  *           at the prompt.  i call these local and global macros.  a global
  483.  *           macro is when this function is called from a running macro.
  484.  *           the running macro can enter text and return from this function
  485.  *           w/o any action from the user.  a local macro is when the user
  486.  *           presses a key inside this function, which happens quite often
  487.  *           when keys are assigned to ASCII and Extended ASCII characters.
  488.  */
  489. int  get_name( char *prompt, int line, char *name, int color )
  490. {
  491. int  col;               /* cursor column for answer */
  492. int  c;                 /* character user just typed */
  493. char *cp;               /* cursor position in answer */
  494. char *answer;           /* user's answer */
  495. int first = TRUE;       /* first character typed */
  496. register int len;       /* length of answer */
  497. int  plen;              /* length of prompt */
  498. int  func;              /* function of key pressed */
  499. int  stop;              /* flag to stop getting characters */
  500. char *p;                /* for copying text in answer */
  501. char buffer[MAX_COLS+2];/* line on which name is being entered */
  502. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  503. int  normal;
  504. int  local_macro = FALSE;
  505. int  next;
  506. int  regx_help_on;
  507. char **pp;
  508. int  i;
  509.  
  510.    /*
  511.     * set up prompt and default
  512.     */
  513.    assert( strlen( prompt ) < MAX_COLS );
  514.    assert( strlen( name )   < MAX_COLS );
  515.  
  516.    strcpy( buffer, prompt );
  517.    plen = strlen( prompt );
  518.    answer = buffer + plen;
  519.    strcpy( answer, name );
  520.  
  521.    /*
  522.     * let user edit default string
  523.     */
  524.    regx_help_on = FALSE;
  525.    len = strlen( answer );
  526.    col = strlen( buffer );
  527.    g_status.prompt_line = line;
  528.    g_status.prompt_col = col;
  529.    cp = answer + len;
  530.    normal = g_display.text_color;
  531.    save_screen_line( 0, line, line_buff );
  532.    s_output( buffer, line, 0, color );
  533.    eol_clear( col, line, normal );
  534.    for (stop = FALSE; stop == FALSE;) {
  535.       if (regx_help_on == TRUE)
  536.          xygoto( -1, -1 );
  537.       else
  538.          xygoto( col, line );
  539.       if (g_status.macro_executing) {
  540.          next = g_status.macro_next;
  541.          g_status.macro_next = macro.strokes[g_status.macro_next].next;
  542.          if (g_status.macro_next != -1) {
  543.             c = macro.strokes[g_status.macro_next].key;
  544.             func = getfunc( c );
  545.             if (func == PlayBack) {
  546.                stop = TRUE;
  547.                g_status.macro_next = next;
  548.             }
  549.          } else {
  550.             c = 0x100;
  551.             func = AbortCommand;
  552.             stop = TRUE;
  553.          }
  554.       } else {
  555.          if (local_macro == FALSE) {
  556.             c = getkey( );
  557.             func = getfunc( c );
  558.  
  559.             /*
  560.              * User may have redefined the Enter and ESC keys.  Make the Enter
  561.              *  key perform a Rturn in this function. Make the ESC key do an
  562.              *  AbortCommand.
  563.              */
  564.             if (c == RTURN)
  565.                func = Rturn;
  566.             else if (c == ESC)
  567.                func = AbortCommand;
  568.  
  569.             if (func == PlayBack) {
  570.                local_macro = TRUE;
  571.                next = macro.first_stroke[ c-256 ];
  572.                c = macro.strokes[next].key;
  573.                func = getfunc( c );
  574.                next = macro.strokes[next].next;
  575.             } else {
  576.                g_status.key_pressed = c;
  577.                record_keys( line );
  578.             }
  579.          } else {
  580.             if (next != -1) {
  581.                c = macro.strokes[next].key;
  582.                next = macro.strokes[next].next;
  583.             } else {
  584.                local_macro = FALSE;
  585.                c = 0x100;
  586.             }
  587.             func = getfunc( c );
  588.          }
  589.       }
  590.       if (c == _F1)
  591.          func = Help;
  592.       if (regx_help_on == TRUE  &&  g_status.current_window != NULL) {
  593.          redraw_screen( g_status.current_window );
  594.          s_output( buffer, line, 0, color );
  595.          eol_clear( col, line, normal );
  596.          s_output( cp, line, col, color );
  597.          regx_help_on = FALSE;
  598.       } else {
  599.          switch (func) {
  600.             case Help :
  601.                if (g_status.command == FindRegX  &&  regx_help_on == FALSE) {
  602.                   regx_help_on = TRUE;
  603.                   for (i=3,pp=regx_help; *pp != NULL; pp++, i++)
  604.                      s_output( *pp, i, 12, g_display.help_color );
  605.                }
  606.                break;
  607.             case ToggleSearchCase :
  608.                mode.search_case = mode.search_case == IGNORE ? MATCH : IGNORE;
  609.                build_boyer_array( );
  610.                show_search_case( );
  611.                break;
  612.             case Rturn       :
  613.             case NextLine    :
  614.             case BegNextLine :
  615.                answer[len] = '\0';
  616.                assert( strlen( answer ) < MAX_COLS );
  617.                strcpy( name, answer );
  618.                /*
  619.                 * finished
  620.                 */
  621.                stop = TRUE;
  622.                break;
  623.             case BackSpace :
  624.                /*
  625.                 * delete to left of cursor
  626.                 */
  627.                if (cp > answer) {
  628.                   for (p=cp-1; p < answer+len; p++) {
  629.                      *p = *(p+1);
  630.                   }
  631.                   --len;
  632.                   --col;
  633.                   --cp;
  634.                   c_output( ' ', plen+len, line, normal );
  635.                   s_output( cp, line, col, color );
  636.                   *(answer + len) = '\0';
  637.                }
  638.                break;
  639.             case DeleteChar :
  640.                /*
  641.                 * delete char under cursor
  642.                 */
  643.                if (*cp) {
  644.                   for (p=cp; p < answer+len; p++) {
  645.                      *p = *(p+1);
  646.                   }
  647.                   --len;
  648.                   c_output( ' ', plen+len, line, normal );
  649.                   s_output( cp, line, col, color );
  650.                   *(answer + len) = '\0';
  651.                }
  652.                break;
  653.             case DeleteLine :
  654.                /*
  655.                 * delete current line
  656.                 */
  657.                col = plen;
  658.                cp = answer;
  659.                *cp = '\0';
  660.                len = 0;
  661.                eol_clear( col, line, normal );
  662.                break;
  663.             case AbortCommand :
  664.                stop = TRUE;
  665.                break;
  666.             case CharLeft :
  667.                /*
  668.                 * move cursor left
  669.                 */
  670.                if (cp > answer) {
  671.                   col--;
  672.                   cp--;
  673.                }
  674.                break;
  675.             case CharRight :
  676.                /*
  677.                 * move cursor right
  678.                 */
  679.                if (*cp) {
  680.                   col++;
  681.                   cp++;
  682.                 }
  683.                 break;
  684.             case BegOfLine :
  685.                /*
  686.                 * move cursor to start of line
  687.                 */
  688.                col = plen;
  689.                cp = answer;
  690.                break;
  691.             case EndOfLine :
  692.                /*
  693.                 * move cursor to end of line
  694.                 */
  695.                col = plen + len;
  696.                cp = answer + len;
  697.                break;
  698.             default :
  699.                if (c < 0x100) {
  700.                   /*
  701.                    * insert character at cursor
  702.                    */
  703.                   if (first) {
  704.                      /*
  705.                       * delete previous answer
  706.                       */
  707.                      col = plen;
  708.                      cp = answer;
  709.                      *cp = '\0';
  710.                      len = 0;
  711.                      eol_clear( col, line, normal );
  712.                   }
  713.  
  714.                   /*
  715.                    * insert new character
  716.                    */
  717.                   if (col < g_display.ncols-1) {
  718.                      if (*cp == '\0') {
  719.                         ++len;
  720.                         *(answer + len) = '\0';
  721.                      }
  722.                      *cp = (char)c;
  723.                      c_output( c, col, line, color );
  724.                      ++cp;
  725.                      ++col;
  726.                   }
  727.                }
  728.                break;
  729.          }
  730.       }
  731.       first = FALSE;
  732.    }
  733.    restore_screen_line( 0, line, line_buff );
  734.    return( func == AbortCommand ? ERROR : OK );
  735. }
  736.  
  737.  
  738. /*
  739.  * Name:    get_sort_order
  740.  * Purpose: To prompt the user and get sort direction
  741.  * Date:    June 5, 1992
  742.  * Passed:  window
  743.  * Returns: OK if user entered something
  744.  *          ERROR if user aborted the command
  745.  */
  746. int  get_sort_order( WINDOW *window )
  747. {
  748. register int c;
  749. int  col;
  750. char line_buff[(MAX_COLS+1)*2];         /* buffer for char and attribute  */
  751.  
  752.    save_screen_line( 0, window->bottom_line, line_buff );
  753.    /*
  754.     * sort ascending or descending
  755.     */
  756.    s_output( utils4, window->bottom_line, 0, g_display.message_color );
  757.    c = strlen( utils4 );
  758.    eol_clear( c, window->bottom_line, g_display.text_color );
  759.    xygoto( c, window->bottom_line );
  760.    do {
  761.       c = getkey( );
  762.       col = getfunc( c );
  763.       if (c == ESC)
  764.          col = AbortCommand;
  765.    } while (col != AbortCommand  &&  c != 'A'  &&  c != 'a'  &&
  766.             c != 'D'  &&  c != 'd');
  767.    switch ( c ) {
  768.       case 'A' :
  769.       case 'a' :
  770.          sort.direction = ASCENDING;
  771.          break;
  772.       case 'D' :
  773.       case 'd' :
  774.          sort.direction = DESCENDING;
  775.          break;
  776.       default  :
  777.          col = AbortCommand;
  778.          break;
  779.    }
  780.    restore_screen_line( 0, window->bottom_line, line_buff );
  781.    return( col == AbortCommand ? ERROR : OK );
  782. }
  783.  
  784.  
  785. /*
  786.  * Name:    get_replace_direction
  787.  * Purpose: To prompt the user and get replace string direction
  788.  * Date:    October 31, 1992
  789.  * Passed:  window
  790.  * Returns: OK if user entered something
  791.  *          ERROR if user aborted the command
  792.  */
  793. int  get_replace_direction( WINDOW *window )
  794. {
  795. register int c;
  796. int  col;
  797. char line_buff[(MAX_COLS+1)*2];         /* buffer for char and attribute  */
  798.  
  799.    save_screen_line( 0, window->bottom_line, line_buff );
  800.    /*
  801.     * replace forward or backward
  802.     */
  803.    s_output( utils5, window->bottom_line, 0, g_display.message_color );
  804.    c = strlen( utils5 );
  805.    eol_clear( c, window->bottom_line, g_display.text_color );
  806.    xygoto( c, window->bottom_line );
  807.    do {
  808.       c = getkey( );
  809.       col = getfunc( c );
  810.       if (c == ESC)
  811.          col = AbortCommand;
  812.    } while (col != AbortCommand  &&  c != 'F'  &&  c != 'f'  &&
  813.             c != 'B'  &&  c != 'b');
  814.    switch ( c ) {
  815.       case 'F' :
  816.       case 'f' :
  817.          c = FORWARD;
  818.          break;
  819.       case 'B' :
  820.       case 'b' :
  821.          c = BACKWARD;
  822.          break;
  823.       default  :
  824.          c = ERROR;
  825.    }
  826.    restore_screen_line( 0, window->bottom_line, line_buff );
  827.    return( col == AbortCommand ? ERROR : c );
  828. }
  829.  
  830.  
  831. /*
  832.  * Name:    get_yn
  833.  * Purpose: To input a response of yes or no.
  834.  * Date:    October 1, 1989
  835.  * Returns: the user's answer.  A_??? - see tdestr.h
  836.  */
  837. int  get_yn( void )
  838. {
  839. int  c;                 /* the user's response */
  840. register int rc;        /* return code */
  841.  
  842.    do {
  843.       c = getkey( );
  844.       rc = getfunc( c );
  845.       if (c== ESC)
  846.          rc = AbortCommand;
  847.    } while (rc != AbortCommand  &&  c != 'Y'  &&  c != 'y'  &&
  848.             c != 'N'  &&  c != 'n');
  849.    if (rc == AbortCommand || c == ESC)
  850.       rc = ERROR;
  851.    else {
  852.       switch ( c ) {
  853.          case 'Y' :
  854.          case 'y' :
  855.             rc = A_YES;
  856.             break;
  857.          case 'N' :
  858.          case 'n' :
  859.             rc = A_NO;
  860.             break;
  861.       }
  862.    }
  863.    return( rc );
  864. }
  865.  
  866.  
  867. /*
  868.  * Name:    get_lr
  869.  * Purpose: To input a response of yes or no.
  870.  * Date:    June 1, 1991
  871.  * Returns: the user's answer, LEFT or RIGHT.
  872.  */
  873. int  get_lr( void )
  874. {
  875. int  c;                 /* the user's response */
  876. register int rc;        /* return code */
  877.  
  878.    for (rc=OK; rc == OK;) {
  879.       c = getkey( );
  880.       if (getfunc( c ) == AbortCommand || c == ESC)
  881.          rc = ERROR;
  882.       else {
  883.          switch ( c ) {
  884.             case 'L' :
  885.             case 'l' :
  886.                rc = LEFT;
  887.                break;
  888.             case 'R' :
  889.             case 'r' :
  890.                rc = RIGHT;
  891.                break;
  892.          }
  893.       }
  894.    }
  895.    return( rc );
  896. }
  897.  
  898.  
  899. /*
  900.  * Name:    get_bc
  901.  * Purpose: To input a response of beginning or current cursor postion
  902.  * Date:    October 31, 1992
  903.  * Returns: the user's answer, Beginning or Current.
  904.  */
  905. int  get_bc( void )
  906. {
  907. int  c;                 /* the user's response */
  908. register int rc;        /* return code */
  909.  
  910.    for (rc=OK; rc == OK;) {
  911.       c = getkey( );
  912.       if (getfunc( c ) == AbortCommand || c == ESC)
  913.          rc = ERROR;
  914.       else {
  915.          switch ( c ) {
  916.             case 'B' :
  917.             case 'b' :
  918.                rc = BEGINNING;
  919.                break;
  920.             case 'C' :
  921.             case 'c' :
  922.                rc = CURRENT;
  923.                break;
  924.          }
  925.       }
  926.    }
  927.    return( rc );
  928. }
  929.  
  930.  
  931. /*
  932.  * Name:    get_oa
  933.  * Purpose: To input a response of overwrite or append.
  934.  * Date:    October 1, 1989
  935.  * Returns: the user's answer.  A_??? - see tdestr.h
  936.  */
  937. int  get_oa( void )
  938. {
  939. int  c;                 /* the user's response */
  940. register int rc;        /* return code */
  941. int  func;
  942.  
  943.    rc = 0;
  944.    while (rc != AbortCommand && rc != A_OVERWRITE && rc != A_APPEND) {
  945.       c = getkey( );
  946.       func = getfunc( c );
  947.       if (func == AbortCommand || c == ESC)
  948.          rc = AbortCommand;
  949.       switch ( c ) {
  950.          case 'O' :
  951.          case 'o' :
  952.             rc = A_OVERWRITE;
  953.             break;
  954.          case 'A' :
  955.          case 'a' :
  956.             rc = A_APPEND;
  957.             break;
  958.       }
  959.    }
  960.    return( rc );
  961. }
  962.  
  963.  
  964. /*
  965.  * Name:    show_eof
  966.  * Purpose: display eof message
  967.  * Date:    September 16, 1991
  968.  * Notes:   line:  ususally, line to is display "<=== eof ===>"
  969.  */
  970. void show_eof( WINDOW *window )
  971. {
  972. register int color;
  973. char temp[MAX_COLS+2];
  974.  
  975.    assert( strlen( mode.eof ) < MAX_COLS );
  976.  
  977.    strcpy( temp, mode.eof );
  978.    color = window->end_col + 1 - window->start_col;
  979.    if (strlen( temp ) > (unsigned)color)
  980.       temp[color] = '\0';
  981.    color = g_display.eof_color;
  982.    window_eol_clear( window, color );
  983.    s_output( temp, window->cline, window->start_col, color );
  984. }
  985.  
  986.  
  987. /*
  988.  * Name:    display_current_window
  989.  * Purpose: display text in current window
  990.  * Date:    June 5, 1991
  991.  * Passed:  window:  pointer to current window
  992.  * Notes:   use a temporary window structure, "w", to do the dirty work.
  993.  */
  994. void display_current_window( WINDOW *window )
  995. {
  996. int  count;     /* number of lines updated so far */
  997. int  number;    /* number of lines visible in window */
  998. register int i; /* register variable */
  999. WINDOW w;       /* scratch window structure */
  1000. int  curl;      /* current line on screen, window->cline */
  1001. int  eof;
  1002.  
  1003.    /*
  1004.     * initialize the scratch variables
  1005.     */
  1006.    number = window->bottom_line - ((window->top_line + window->ruler) - 1);
  1007.    count  = window->cline - (window->top_line + window->ruler);
  1008.    dup_window_info( &w, window );
  1009.  
  1010.    w.cline -= count;
  1011.    w.rline -= count;
  1012.    for (eof=count; eof > 0; eof--)
  1013.       w.ll = w.ll->prev;
  1014.  
  1015.  
  1016.    /*
  1017.     * start at the top of the window and display a window full of text
  1018.     */
  1019.    eof = FALSE;
  1020.    curl = window->cline;
  1021.    for (i=number; i>0; i--) {
  1022.       if (w.ll->len != EOF) {
  1023.          /*
  1024.           * if this is window->cline, do not show the line because we
  1025.           *  show the curl at the end of this function.  don't show it twice
  1026.           */
  1027.          if (w.cline != curl)
  1028.             update_line( &w );
  1029.          w.ll = w.ll->next;
  1030.       } else if (eof == FALSE) {
  1031.          show_eof( &w );
  1032.          eof = TRUE;
  1033.       } else
  1034.          window_eol_clear( &w, COLOR_TEXT );
  1035.       ++w.cline;
  1036.       ++w.rline;
  1037.    }
  1038.    show_asterisk( window );
  1039.    show_curl_line( window );
  1040. }
  1041.  
  1042.  
  1043. /*
  1044.  * Name:    redraw_screen
  1045.  * Purpose: display all visible windows, modes, and headers
  1046.  * Date:    June 5, 1991
  1047.  * Passed:  window:  pointer to current window
  1048.  */
  1049. int  redraw_screen( WINDOW *window )
  1050. {
  1051. register WINDOW *above;        /* window above current */
  1052. register WINDOW *below;        /* window below current */
  1053.  
  1054.    cls( );
  1055.    /*
  1056.     * display the current window
  1057.     */
  1058.    redraw_current_window( window );
  1059.  
  1060.    /*
  1061.     * now update all the other windows
  1062.     */
  1063.    above = below = window;
  1064.    while (above->prev || below->next) {
  1065.       if (above->prev) {
  1066.          above = above->prev;
  1067.          redraw_current_window( above );
  1068.       }
  1069.       if (below->next) {
  1070.          below = below->next;
  1071.          redraw_current_window( below );
  1072.       }
  1073.    }
  1074.    window->file_info->dirty = FALSE;
  1075.    show_modes( );
  1076.    return( OK );
  1077. }
  1078.  
  1079.  
  1080. /*
  1081.  * Name:    redraw_current_window
  1082.  * Purpose: redraw all info in window
  1083.  * Date:    July 13, 1991
  1084.  * Passed:  window:  pointer to current window
  1085.  */
  1086. void redraw_current_window( WINDOW *window )
  1087. {
  1088.  
  1089.    /*
  1090.     * display the current window
  1091.     */
  1092.    if (window->visible) {
  1093.       display_current_window( window );
  1094.       show_window_header( window );
  1095.       show_ruler( window );
  1096.       show_ruler_pointer( window );
  1097.       if (window->vertical)
  1098.          show_vertical_separator( window );
  1099.    }
  1100. }
  1101.  
  1102.  
  1103. /*
  1104.  * Name:    show_changed_line
  1105.  * Purpose: Only one line was changed in file, just show it
  1106.  * Date:    June 5, 1991
  1107.  * Passed:  window:  pointer to current window
  1108.  */
  1109. void show_changed_line( WINDOW *window )
  1110. {
  1111. WINDOW *above;                  /* window above current */
  1112. WINDOW *below;                  /* window below current */
  1113. WINDOW w;                       /* scratch window structure */
  1114. long changed_line;              /* line number in file that was changed */
  1115. long top_line, bottom_line;     /* top and bottom line in file on screen */
  1116. int  line_on_screen;            /* is changed line on screen? */
  1117. file_infos *file;               /* file pointer */
  1118.  
  1119.    file = window->file_info;
  1120.    if ((file->dirty == LOCAL || file->dirty == GLOBAL) && window->visible)
  1121.       show_curl_line( window );
  1122.    changed_line = window->rline;
  1123.  
  1124.    /*
  1125.     * now update the line in all other windows
  1126.     */
  1127.    if (file->dirty != LOCAL) {
  1128.       above = below = window;
  1129.       while (above->prev || below->next) {
  1130.          if (above->prev) {
  1131.             above = above->prev;
  1132.             dup_window_info( &w, above );
  1133.          } else if (below->next) {
  1134.             below = below->next;
  1135.             dup_window_info( &w, below );
  1136.          }
  1137.  
  1138.          /*
  1139.           * is this window the changed file and is it visible?
  1140.           */
  1141.          if (w.file_info == file && w.visible) {
  1142.  
  1143.             /*
  1144.              * calculate file lines at top and bottom of screen.
  1145.              * the changed line may not be the curl in other windows.
  1146.              */
  1147.             line_on_screen = FALSE;
  1148.             top_line = w.rline - (w.cline - (w.top_line + w.ruler));
  1149.             bottom_line = w.rline + (w.bottom_line - w.cline);
  1150.             if (changed_line == w.rline)
  1151.                line_on_screen = CURLINE;
  1152.             else if (changed_line < w.rline && changed_line >= top_line) {
  1153.                line_on_screen = NOTCURLINE;
  1154.                while (w.rline > changed_line) {
  1155.                   w.ll = w.ll->prev;
  1156.                   --w.rline;
  1157.                   --w.cline;
  1158.                }
  1159.             } else if (changed_line > w.rline && changed_line <= bottom_line) {
  1160.                line_on_screen = NOTCURLINE;
  1161.                while (w.rline < changed_line) {
  1162.                   w.ll = w.ll->next;
  1163.                   ++w.rline;
  1164.                   ++w.cline;
  1165.                }
  1166.             }
  1167.  
  1168.             /*
  1169.              * display the changed line if on screen
  1170.              */
  1171.             if (line_on_screen == NOTCURLINE)
  1172.                update_line( &w );
  1173.             else if (line_on_screen == CURLINE)
  1174.                show_curl_line( &w );
  1175.          }
  1176.       }
  1177.    }
  1178.    file->dirty = FALSE;
  1179. }
  1180.  
  1181.  
  1182. /*
  1183.  * Name:    show_curl_line
  1184.  * Purpose: show current line in curl color
  1185.  * Date:    January 16, 1992
  1186.  * Passed:  window:  pointer to current window
  1187.  */
  1188. void show_curl_line( WINDOW *window )
  1189. {
  1190. int  text_color;
  1191. int  dirty_color;
  1192.  
  1193.    if (window->visible  &&  g_status.screen_display) {
  1194.       text_color = g_display.text_color;
  1195.       dirty_color = g_display.dirty_color;
  1196.       g_display.dirty_color = g_display.text_color = g_display.curl_color;
  1197.       update_line( window );
  1198.       g_display.text_color = text_color;
  1199.       g_display.dirty_color = dirty_color;
  1200.    }
  1201. }
  1202.  
  1203.  
  1204. /*
  1205.  * Name:    dup_window_info
  1206.  * Purpose: Copy window info from one window pointer to another
  1207.  * Date:    June 5, 1991
  1208.  * Passed:  dw: destination window
  1209.  *          sw: source window
  1210.  */
  1211. void dup_window_info( WINDOW *dw, WINDOW *sw )
  1212. {
  1213.    memcpy( dw, sw, sizeof( WINDOW ) );
  1214. }
  1215.  
  1216.  
  1217. /*
  1218.  * Name:    adjust_windows_cursor
  1219.  * Purpose: A change has been made, make sure pointers are not ahead of
  1220.  *           or behind file.
  1221.  * Date:    June 5, 1991
  1222.  * Passed:  window:       pointer to current window
  1223.  *          line_change:  number of lines add to or subtracted from file
  1224.  * Notes:   If a file has been truncated in one window and there is another
  1225.  *           window open to the same file and its current line is near the
  1226.  *           end, the current line is reset to the last line of the file.
  1227.  */
  1228. void adjust_windows_cursor( WINDOW *window, long line_change )
  1229. {
  1230. register WINDOW *next;
  1231. long i;
  1232. file_infos *file;
  1233. MARKER *marker;
  1234. long length;
  1235.  
  1236.    file = window->file_info;
  1237.    length = file->length;
  1238.    next = g_status.window_list;
  1239.    while (next != NULL) {
  1240.       if (next != window) {
  1241.          if (next->file_info == file) {
  1242.             if (next->rline > length + 1) {
  1243.                next->rline = length;
  1244.                next->ll    = file->line_list_end;
  1245.                file->dirty = NOT_LOCAL;
  1246.             } else if (next->rline < 1) {
  1247.                next->rline = 1;
  1248.                next->cline = next->top_line + next->ruler;
  1249.                next->ll    = file->line_list;
  1250.                next->bin_offset = 0;
  1251.                file->dirty = NOT_LOCAL;
  1252.             }
  1253.             if (next->rline > window->rline  &&  line_change) {
  1254.                file->dirty = NOT_LOCAL;
  1255.                if (line_change < 0) {
  1256.                   for (i=line_change; i < 0 && next->ll->next != NULL; i++) {
  1257.                      next->bin_offset += next->ll->len;
  1258.                      next->ll = next->ll->next;
  1259.                   }
  1260.                } else if (line_change > 0) {
  1261.                   for (i=line_change; i > 0 && next->ll->prev != NULL; i--) {
  1262.                      next->ll = next->ll->prev;
  1263.                      next->bin_offset -= next->ll->len;
  1264.                   }
  1265.                }
  1266.             }
  1267.             if (next->rline < (next->cline -(next->top_line+next->ruler-1))) {
  1268.                next->cline = (int)next->rline+(next->top_line+next->ruler)-1;
  1269.                file->dirty = NOT_LOCAL;
  1270.             }
  1271.          }
  1272.       }
  1273.       next = next->next;
  1274.    }
  1275.  
  1276.    /*
  1277.     * now adjust any markers.
  1278.     */
  1279.    for (i=0; i<3; i++) {
  1280.       marker = &file->marker[ (int) i ];
  1281.       if (marker->rline > window->rline) {
  1282.          marker->rline += line_change;
  1283.          if (marker->rline < 1L)
  1284.             marker->rline = 1L;
  1285.          else if (marker->rline > length)
  1286.             marker->rline = length;
  1287.       }
  1288.    }
  1289. }
  1290.  
  1291.  
  1292. /*
  1293.  * Name:    first_non_blank
  1294.  * Purpose: To find the column of the first non-blank character
  1295.  * Date:    June 5, 1991
  1296.  * Passed:  s:    the string to search
  1297.  *          len:  length of string
  1298.  * Returns: the first non-blank column
  1299.  */
  1300. int  first_non_blank( text_ptr s, int len )
  1301. {
  1302. register int count = 0;
  1303.  
  1304.    if (s != NULL) {
  1305.       if (mode.inflate_tabs) {
  1306.          for (; len > 0 && (*s == ' ' || *s == '\t'); s++, len--) {
  1307.             if (*s != '\t')
  1308.                ++count;
  1309.             else
  1310.                count += mode.ptab_size - (count % mode.ptab_size);
  1311.          }
  1312.       } else {
  1313.          while (len-- > 0  &&  *s++ == ' ')
  1314.            ++count;
  1315.       }
  1316.    }
  1317.    return( count );
  1318. }
  1319.  
  1320.  
  1321. /*
  1322.  * Name:    find_end
  1323.  * Purpose: To find the last character in a line
  1324.  * Date:    October 31, 1992
  1325.  * Passed:  s:    the string to search
  1326.  *          len:  length of string
  1327.  * Returns: the first non-blank column
  1328.  */
  1329. int  find_end( text_ptr s, int len )
  1330. {
  1331. register int count = 0;
  1332.  
  1333.    if (s != NULL) {
  1334.       if (mode.inflate_tabs) {
  1335.          for (;len > 0; s++, len--) {
  1336.             if (*s == '\t')
  1337.                count += mode.ptab_size - (count % mode.ptab_size);
  1338.             else
  1339.                ++count;
  1340.          }
  1341.       } else
  1342.          count = len;
  1343.    }
  1344.    return( count );
  1345. }
  1346.  
  1347.  
  1348. /*
  1349.  * Name:    is_line_blank
  1350.  * Purpose: is line empty or does it only contain spaces?
  1351.  * Date:    November 28, 1991
  1352.  * Passed:  s:    the string to search
  1353.  *          len:  length of string
  1354.  * Returns: TRUE if line is blank or FALSE if something is in line
  1355.  */
  1356. int is_line_blank( text_ptr s, int len )
  1357. {
  1358.    if (s != NULL) {
  1359.       if (mode.inflate_tabs) {
  1360.         while (len > 0  &&  (*s == ' ' || *s == '\t')) {
  1361.            ++s;
  1362.            --len;
  1363.         }
  1364.       } else {
  1365.          while (len > 0  &&  *s == ' ') {
  1366.             ++s;
  1367.             --len;
  1368.          }
  1369.       }
  1370.    } else
  1371.       len = 0;
  1372.    return( len == 0 );
  1373. }
  1374.  
  1375.  
  1376. /*
  1377.  * Name:    page_up
  1378.  * Purpose: To move the cursor one page up the window
  1379.  * Date:    June 5, 1991
  1380.  * Passed:  window:  pointer to current window
  1381.  * Notes:   The cursor line is moved back the required number of lines
  1382.  *           towards the start of the file.
  1383.  *          If the start of the file is reached, then movement stops.
  1384.  */
  1385. int  page_up( WINDOW *window )
  1386. {
  1387. int  i;                 /* count of lines scanned */
  1388. int  rc = OK;           /* default return code */
  1389. register WINDOW *win;   /* put window pointer in a register */
  1390. long number;
  1391. long len;
  1392.  
  1393.    win = window;
  1394.    entab_linebuff( );
  1395.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1396.       return( ERROR );
  1397.    if (win->rline != (win->cline - (win->top_line + win->ruler - 1))) {
  1398.       i = win->cline - (win->top_line + win->ruler - 1);
  1399.       number = win->rline;
  1400.       if (( win->rline - i) < win->page)
  1401.          win->rline = (win->cline-(win->top_line + win->ruler -1)) + win->page;
  1402.       win->rline -= win->page;
  1403.       for (len =0, i=(int)(number - win->rline); i>0; i--)
  1404.          if (win->ll->prev != NULL) {
  1405.             win->ll = win->ll->prev;
  1406.             len -= win->ll->len;
  1407.          }
  1408.       win->file_info->dirty = LOCAL;
  1409.       win->bin_offset += len;
  1410.    } else
  1411.       rc = ERROR;
  1412.    sync( win );
  1413.    return( rc );
  1414. }
  1415.  
  1416.  
  1417. /*
  1418.  * Name:    page_down
  1419.  * Purpose: To move the cursor one page down the window
  1420.  * Date:    June 5, 1991
  1421.  * Passed:  window:  pointer to current window
  1422.  * Notes:   The cursor line is moved forwards the required number of lines
  1423.  *           towards the end of the file.
  1424.  *          If the end of the file is reached, then movement stops.
  1425.  */
  1426. int  page_down( WINDOW *window )
  1427. {
  1428. int  i;                 /* count of lines scanned so far */
  1429. int  k;
  1430. int  rc = OK;
  1431. long len;
  1432. register WINDOW *win;  /* put window pointer in a register */
  1433. line_list_ptr p;
  1434.  
  1435.    win = window;
  1436.    entab_linebuff( );
  1437.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1438.       return( ERROR );
  1439.    p = win->ll;
  1440.    k = win->cline - (win->top_line + win->ruler);
  1441.    for (len=i=0; i < win->page && p->next != NULL; i++, k++, p=p->next)
  1442.       if (p->len != EOF)
  1443.          len += p->len;
  1444.    if (k >= win->page) {
  1445.       win->rline += i;
  1446.       win->cline = win->cline + i - win->page;
  1447.       win->bin_offset += len;
  1448.       win->ll = p;
  1449.       win->file_info->dirty = LOCAL;
  1450.    } else
  1451.       rc = ERROR;
  1452.    sync( win );
  1453.    return( rc );
  1454. }
  1455.  
  1456.  
  1457. /*
  1458.  * Name:    scroll_down
  1459.  * Purpose: scroll window down one line
  1460.  * Date:    June 5, 1991
  1461.  * Passed:  window:  pointer to current window
  1462.  * Notes:   If there is a line to scroll_down, make the window LOCAL dirty.
  1463.  *          We have to redraw the screen anyway, so don't update here.
  1464.  */
  1465. int  scroll_down( WINDOW *window )
  1466. {
  1467. int  rc = OK;
  1468. register WINDOW *win;   /* put window pointer in a register */
  1469.  
  1470.    win = window;
  1471.    entab_linebuff( );
  1472.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1473.       return( ERROR );
  1474.    if (win->cline == win->top_line + win->ruler) {
  1475.       if (win->ll->next != NULL) {
  1476.          ++win->rline;
  1477.          win->bin_offset += win->ll->len;
  1478.          win->ll = win->ll->next;
  1479.          win->file_info->dirty = LOCAL;
  1480.       } else
  1481.          rc = ERROR;
  1482.    } else {
  1483.       --win->cline;
  1484.       win->file_info->dirty = LOCAL;
  1485.    }
  1486.    sync( win );
  1487.    return( rc );
  1488. }
  1489.  
  1490.  
  1491. /*
  1492.  * Name:    scroll_up
  1493.  * Purpose: To scroll the window up one line
  1494.  * Date:    June 5, 1991
  1495.  * Passed:  window:  pointer to current window
  1496.  * Notes:   If this is the first page, then update screen here.  Else, make
  1497.  *           the window LOCAL dirty because we have to redraw screen.
  1498.  */
  1499. int  scroll_up( WINDOW *window )
  1500. {
  1501. int  rc = OK;
  1502. register WINDOW *win;   /* put window pointer in a register */
  1503.  
  1504.    win = window;
  1505.    entab_linebuff( );
  1506.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1507.       return( ERROR );
  1508.    if (win->rline > 1) {
  1509.       if (win->rline == (win->cline - (win->top_line + win->ruler - 1))) {
  1510.          if (!mode.sync)
  1511.             update_line( win );
  1512.          win->ll = win->ll->prev;
  1513.          win->bin_offset -= win->ll->len;
  1514.          --win->rline;
  1515.          --win->cline;
  1516.          if (!mode.sync)
  1517.             show_curl_line( win );
  1518.       } else {
  1519.          if (win->cline == win->bottom_line) {
  1520.             --win->rline;
  1521.             win->ll = win->ll->prev;
  1522.             win->bin_offset -= win->ll->len;
  1523.             win->file_info->dirty = LOCAL;
  1524.          } else {
  1525.             ++win->cline;
  1526.             win->file_info->dirty = LOCAL;
  1527.          }
  1528.       }
  1529.    } else
  1530.      rc = ERROR;
  1531.    sync( win );
  1532.    return( rc );
  1533. }
  1534.  
  1535.  
  1536. /*
  1537.  * Name:    pan_up
  1538.  * Purpose: To leave cursor on same logical line and scroll text up
  1539.  * Date:    September 1, 1991
  1540.  * Passed:  window:  pointer to current window
  1541.  * Notes:   If cursor is on first page then do not scroll.
  1542.  */
  1543. int  pan_up( WINDOW *window )
  1544. {
  1545. int  rc = OK;
  1546. register WINDOW *win;   /* put window pointer in a register */
  1547.  
  1548.    win = window;
  1549.    entab_linebuff( );
  1550.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1551.       return( ERROR );
  1552.  
  1553.    /*
  1554.     * see if cursor is on the first page. if it's not then pan_up.
  1555.     */
  1556.    if (win->rline != (win->cline+1 - (win->top_line + win->ruler))) {
  1557.       if (win->rline > 1) {
  1558.          --win->rline;
  1559.          win->ll = win->ll->prev;
  1560.          win->bin_offset -= win->ll->len;
  1561.          win->file_info->dirty = LOCAL;
  1562.       }
  1563.    } else
  1564.       rc = ERROR;
  1565.    sync( win );
  1566.    return( rc );
  1567. }
  1568.  
  1569.  
  1570. /*
  1571.  * Name:    pan_down
  1572.  * Purpose: To leave cursor on same logical line and scroll text down
  1573.  * Date:    September 1, 1991
  1574.  * Passed:  window:  pointer to current window
  1575.  * Notes:   If cursor is on last line in file then do not scroll.
  1576.  */
  1577. int  pan_down( WINDOW *window )
  1578. {
  1579. int  rc = OK;
  1580. register WINDOW *win;   /* put window pointer in a register */
  1581.  
  1582.    win = window;
  1583.    entab_linebuff( );
  1584.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1585.       return( ERROR );
  1586.    if (win->ll->len != EOF) {
  1587.       ++win->rline;
  1588.       win->bin_offset += win->ll->len;
  1589.       win->ll = win->ll->next;
  1590.       win->file_info->dirty = LOCAL;
  1591.    } else
  1592.       rc = ERROR;
  1593.    sync( win );
  1594.    return( rc );
  1595. }
  1596.  
  1597.  
  1598. /*
  1599.  * Name:    show_window_header
  1600.  * Purpose: show file stuff in window header
  1601.  * Date:    June 5, 1991
  1602.  * Passed:  window:  pointer to current window
  1603.  * Notes:   Clear line and display header in a lite bar
  1604.  */
  1605. void show_window_header( WINDOW *window )
  1606. {
  1607. char status_line[MAX_COLS+2];   /* status line at top of window */
  1608. register WINDOW *win;           /* put window pointer in a register */
  1609. int  len;
  1610.  
  1611.    win = window;
  1612.    len = win->vertical ? win->end_col + 1 - win->start_col : win->end_col;
  1613.  
  1614.    assert( len >= 0 );
  1615.    assert( len <= MAX_COLS );
  1616.  
  1617.    memset( status_line, ' ', len );
  1618.    status_line[len] = '\0';
  1619.    s_output( status_line, win->top_line-1, win->start_col,g_display.head_color);
  1620.    show_window_number_letter( win );
  1621.    show_window_fname( win );
  1622.    show_crlf_mode( win );
  1623.    show_size( win );
  1624.    show_line_col( win );
  1625. }
  1626.  
  1627.  
  1628. /*
  1629.  * Name:    show_window_number_letter
  1630.  * Purpose: show file number and letter of window in lite bar
  1631.  * Date:    June 5, 1991
  1632.  * Passed:  window:  pointer to current window
  1633.  */
  1634. void show_window_number_letter( WINDOW *window )
  1635. {
  1636. int  col;
  1637. char temp[10];
  1638. register WINDOW *win;   /* put window pointer in a register */
  1639.  
  1640.    win = window;
  1641.    col = win->start_col;
  1642.    s_output( "   ", win->top_line-1, col, g_display.head_color );
  1643.    itoa( win->file_info->file_no, temp, 10 );
  1644.    s_output( temp, win->top_line-1, strlen( temp ) > 1 ? col : col+1,
  1645.              g_display.head_color );
  1646.    c_output( win->letter, col+2, win->top_line-1, g_display.head_color );
  1647. }
  1648.  
  1649.  
  1650. /*
  1651.  * Name:    show_window_fname
  1652.  * Purpose: show file name in window header.
  1653.  * Date:    June 5, 1991
  1654.  * Passed:  window:  pointer to current window
  1655.  * Notes:   Clear name field and display name in a lite bar
  1656.  */
  1657. void show_window_fname( WINDOW *window )
  1658. {
  1659. char status_line[MAX_COLS+2];   /* status line at top of window */
  1660. register int  fattr;
  1661. char *p;
  1662. register WINDOW *win;          /* put window pointer in a register */
  1663. int  col;
  1664. int  len;
  1665.  
  1666.    win = window;
  1667.    col = win->start_col;
  1668.    len = win->vertical ? 11 : FNAME_LENGTH;
  1669.  
  1670.    assert( len >= 0 );
  1671.    assert( len <= MAX_COLS );
  1672.  
  1673.    memset( status_line, ' ', len );
  1674.    status_line[len] = '\0';
  1675.    s_output( status_line, win->top_line-1, col+5, g_display.head_color );
  1676.  
  1677.    assert( strlen( win->file_info->file_name ) < MAX_COLS );
  1678.  
  1679.    strcpy( status_line, win->file_info->file_name );
  1680.    p = status_line;
  1681.    if (win->vertical) {
  1682.       len = strlen( status_line );
  1683.       for (p=status_line+len;*(p-1) != ':' && *(p-1) != '\\' && p>status_line;)
  1684.          --p;
  1685.    } else {
  1686.       status_line[FNAME_LENGTH] = '\0';
  1687.       p = status_line;
  1688.    }
  1689.    s_output( p, win->top_line-1, col+5, g_display.head_color );
  1690.    if (!win->vertical) {
  1691.       fattr = win->file_info->file_attrib;
  1692.       p = status_line;
  1693.       *p++ = (char)(fattr & ARCHIVE   ? 'A' : '-');
  1694.       *p++ = (char)(fattr & SYSTEM    ? 'S' : '-');
  1695.       *p++ = (char)(fattr & HIDDEN    ? 'H' : '-');
  1696.       *p++ = (char)(fattr & READ_ONLY ? 'R' : '-');
  1697.       *p   = '\0';
  1698.       s_output( status_line, win->top_line-1, col+51, g_display.head_color );
  1699.    }
  1700. }
  1701.  
  1702.  
  1703. /*
  1704.  * Name:    show_crlf_mode
  1705.  * Purpose: display state of crlf flag
  1706.  * Date:    June 5, 1991
  1707.  */
  1708. void show_crlf_mode( WINDOW *window )
  1709. {
  1710. char status_line[MAX_COLS+2];   /* status line at top of window */
  1711.  
  1712.    if (!window->vertical) {
  1713.       switch (window->file_info->crlf) {
  1714.          case LF :
  1715.             strcpy( status_line, "lf  " );
  1716.             break;
  1717.          case CRLF :
  1718.             strcpy( status_line, "crlf" );
  1719.             break;
  1720.          case BINARY :
  1721.             strcpy( status_line, "BIN " );
  1722.             break;
  1723.          default :
  1724.             assert( FALSE );
  1725.       }
  1726.       s_output( status_line, window->top_line-1, window->start_col+56,
  1727.                 g_display.head_color );
  1728.    }
  1729. }
  1730.  
  1731.  
  1732. /*
  1733.  * Name:    show_size
  1734.  * Purpose: show number of lines in file
  1735.  * Date:    June 5, 1991
  1736.  * Passed:  window:  pointer to current window
  1737.  */
  1738. void show_size( WINDOW *window )
  1739. {
  1740. char csize[20];
  1741.  
  1742.    if (!window->vertical  &&  window->file_info->crlf != BINARY) {
  1743.       s_output( "       ", window->top_line-1, 61, g_display.head_color );
  1744.       ltoa( window->file_info->length, csize, 10 );
  1745.       s_output( csize, window->top_line-1, 61, g_display.head_color );
  1746.    }
  1747. }
  1748.  
  1749.  
  1750. /*
  1751.  * Name:    quit
  1752.  * Purpose: To close the current window without saving the current file.
  1753.  * Date:    June 5, 1991
  1754.  * Passed:  window:  pointer to current window
  1755.  * Notes:   If the file has been modified but not saved, then the user is
  1756.  *           given a second chance before the changes are discarded.
  1757.  *          Note that this is only necessary if this is the last window
  1758.  *           that refers to the file.  If another window still refers to
  1759.  *           the file, then the check can be left until later.
  1760.  */
  1761. int  quit( WINDOW *window )
  1762. {
  1763. int  prompt_line;
  1764. char line_buff[(MAX_COLS+2)*2]; /* buffer for char and attribute  */
  1765. register file_infos *file;
  1766. WINDOW *wp;
  1767. int  count = 0;
  1768. int  rc = OK;
  1769.  
  1770.    entab_linebuff( );
  1771.    if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  1772.       return( ERROR );
  1773.    prompt_line = window->bottom_line;
  1774.    file = window->file_info;
  1775.    for (wp=g_status.window_list; wp != NULL; wp=wp->next) {
  1776.       if (wp->file_info == file && wp->visible)
  1777.          ++count;
  1778.    }
  1779.    if (file->modified && count == 1) {
  1780.       save_screen_line( 0, prompt_line, line_buff );
  1781.       /*
  1782.        * abandon changes (y/n)
  1783.        */
  1784.       set_prompt( utils12, prompt_line );
  1785.       if (get_yn( ) != A_YES)
  1786.          rc = ERROR;
  1787.       restore_screen_line( 0, prompt_line, line_buff );
  1788.    }
  1789.  
  1790.    /*
  1791.     * remove window, allocate screen lines to other windows etc
  1792.     */
  1793.    if (rc == OK)
  1794.       finish( window );
  1795.    return( OK );
  1796. }
  1797.  
  1798.  
  1799. /*
  1800.  * Name:    move_up
  1801.  * Purpose: To move the cursor up one line
  1802.  * Date:    June 5, 1991
  1803.  * Passed:  window:  pointer to current window
  1804.  * Notes:   If the cursor is at the top of the window, then the file must
  1805.  *           be scrolled down.
  1806.  */
  1807. int  move_up( WINDOW *window )
  1808. {
  1809. int  rc = OK;
  1810. register WINDOW *win;   /* put window pointer in a register */
  1811. int  at_top = FALSE;    /* is cline at top of screen? */
  1812.  
  1813.    win = window;
  1814.    entab_linebuff( );
  1815.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1816.       return( ERROR );
  1817.  
  1818.    /*
  1819.     * if no previous line, give up
  1820.     */
  1821.    if (win->rline > 1) {
  1822.       if (win->cline == win->top_line + win->ruler) {
  1823.          win->file_info->dirty = LOCAL;
  1824.          at_top = TRUE;
  1825.       }
  1826.       if (!at_top)
  1827.          update_line( win );
  1828.       --win->rline;             /* ALWAYS decrement line counter */
  1829.       win->ll = win->ll->prev;
  1830.       win->bin_offset -= win->ll->len;
  1831.       if (!at_top) {
  1832.          --win->cline;          /* we aren't at top of screen - so move up */
  1833.          show_curl_line( win );
  1834.       }
  1835.    } else
  1836.       rc = ERROR;
  1837.    sync( win );
  1838.    return( rc );
  1839. }
  1840.  
  1841.  
  1842. /*
  1843.  * Name:    move_down
  1844.  * Purpose: To move the cursor down one line
  1845.  * Date:    June 5, 1991
  1846.  * Passed:  window:  pointer to current window
  1847.  * Notes:   If the cursor is at the bottom of the window, then the file must
  1848.  *           be scrolled up.   If the cursor is at the bottom of the file,
  1849.  *           then scroll line up until it is at top of screen.
  1850.  */
  1851. int  move_down( WINDOW *window )
  1852. {
  1853. int  rc;
  1854.  
  1855.    rc = prepare_move_down( window );
  1856.    sync( window );
  1857.    return( rc );
  1858. }
  1859.  
  1860.  
  1861. /*
  1862.  * Name:    prepare_move_down
  1863.  * Purpose: Do the stuff needed to move the cursor down one line.
  1864.  * Date:    June 5, 1991
  1865.  * Passed:  window:  pointer to current window
  1866.  * Notes:   Put all the stuff needed to move the cursor down one line in
  1867.  *           one function, so several functions can use the guts of the
  1868.  *           algorithm.
  1869.  */
  1870. int  prepare_move_down( WINDOW *window )
  1871. {
  1872. int  rc = OK;
  1873. register WINDOW *win;   /* put window pointer in a register */
  1874. int  at_bottom = FALSE; /* is cline at bottom of screen */
  1875.  
  1876.    win = window;
  1877.    entab_linebuff( );
  1878.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1879.       return( ERROR );
  1880.    if (win->cline == win->bottom_line) {
  1881.       win->file_info->dirty = LOCAL;
  1882.       at_bottom = TRUE;
  1883.    }
  1884.    if (!at_bottom)
  1885.       update_line( win );
  1886.    if (win->ll->len != EOF) {
  1887.       win->bin_offset += win->ll->len;
  1888.       ++win->rline;             /* ALWAYS increment line counter */
  1889.       win->ll = win->ll->next;
  1890.       if (!at_bottom) {
  1891.          ++win->cline;          /* if not at bottom of screen move down */
  1892.          show_curl_line( win );
  1893.       }
  1894.    } else if (win->cline > win->top_line + win->ruler) {
  1895.       --win->cline;
  1896.       win->file_info->dirty = LOCAL;
  1897.       rc = ERROR;
  1898.    } else
  1899.       rc = ERROR;
  1900.    return( rc );
  1901. }
  1902.  
  1903.  
  1904. /*
  1905.  * Name:    move_left
  1906.  * Purpose: To move the cursor left one character
  1907.  * Date:    June 5, 1991
  1908.  * Passed:  window:  pointer to current window
  1909.  * Notes:   If the cursor is already at the left of the screen, then
  1910.  *           scroll horizontally if we're not at beginning of line.
  1911.  */
  1912. int  move_left( WINDOW *window )
  1913. {
  1914. int  new_ruler = FALSE;
  1915.  
  1916.    if (window->ccol > window->start_col) {
  1917.       show_ruler_char( window );
  1918.       --window->ccol;
  1919.       --window->rcol;
  1920.    } else if (window->ccol == window->start_col && window->rcol > 0) {
  1921.       --window->rcol;
  1922.       --window->bcol;
  1923.       window->file_info->dirty = LOCAL;
  1924.       new_ruler = TRUE;
  1925.    }
  1926.    sync( window );
  1927.    if (new_ruler) {
  1928.       make_ruler( window );
  1929.       show_ruler( window );
  1930.    }
  1931.    return( OK );
  1932. }
  1933.  
  1934.  
  1935. /*
  1936.  * Name:    move_right
  1937.  * Purpose: To move the cursor right one character
  1938.  * Date:    June 5, 1991
  1939.  * Passed:  window:  pointer to current window
  1940.  * Notes:   If the cursor is already at the right of the screen (logical
  1941.  *          column 80) then scroll horizontally right.
  1942.  */
  1943. int  move_right( WINDOW *window )
  1944. {
  1945. int  new_ruler = FALSE;
  1946.  
  1947.    if (window->rcol < g_display.line_length - 1) {
  1948.       if (window->ccol < window->end_col) {
  1949.          show_ruler_char( window );
  1950.          ++window->ccol;
  1951.          ++window->rcol;
  1952.       } else if (window->ccol == window->end_col) {
  1953.          ++window->rcol;
  1954.          ++window->bcol;
  1955.          window->file_info->dirty = LOCAL;
  1956.          new_ruler = TRUE;
  1957.       }
  1958.    }
  1959.    sync( window );
  1960.    if (new_ruler) {
  1961.       make_ruler( window );
  1962.       show_ruler( window );
  1963.    }
  1964.    return( OK );
  1965. }
  1966.  
  1967.  
  1968. /*
  1969.  * Name:    pan_left
  1970.  * Purpose: To pan the screen left one character
  1971.  * Date:    January 5, 1992
  1972.  * Passed:  window:  pointer to current window
  1973.  */
  1974. int  pan_left( WINDOW *window )
  1975. {
  1976. /*
  1977.  * if (window->bcol == 0) {
  1978.  *    if (window->ccol > window->start_col) {
  1979.  *       show_ruler_char( window );
  1980.  *       --window->ccol;
  1981.  *       --window->rcol;
  1982.  *    }
  1983.  * } else if (window->bcol > 0 ) {
  1984.  * * *  Scroll window left function:
  1985.  * * *      --window->bcol;
  1986.  * * *      if (window->ccol < g_display.ncols - 1)
  1987.  * * *         ++window->ccol;
  1988.  * * *      else
  1989.  * * *         --window->rcol;
  1990.  */
  1991.    if (window->bcol > 0 ) {
  1992.       --window->bcol;
  1993.       --window->rcol;
  1994.       window->file_info->dirty = LOCAL;
  1995.       make_ruler( window );
  1996.       show_ruler( window );
  1997.    }
  1998.    sync( window );
  1999.    return( OK );
  2000. }
  2001.  
  2002.  
  2003. /*
  2004.  * Name:    pan_right
  2005.  * Purpose: To pan the screen right one character
  2006.  * Date:    January 5, 1992
  2007.  * Passed:  window:  pointer to current window
  2008.  */
  2009. int  pan_right( WINDOW *window )
  2010. {
  2011.    if (window->rcol < g_display.line_length - 1) {
  2012. /*
  2013.  *      scroll screen right function:
  2014.  *      if (window->ccol > 0)
  2015.  *         --window->ccol;
  2016.  *      else
  2017.  *         ++window->rcol;
  2018.  */
  2019.       ++window->rcol;
  2020.       ++window->bcol;
  2021.       window->file_info->dirty = LOCAL;
  2022.       make_ruler( window );
  2023.       show_ruler( window );
  2024.    }
  2025.    sync( window );
  2026.    return( OK );
  2027. }
  2028.  
  2029.  
  2030. /*
  2031.  * Name:    word_left
  2032.  * Purpose: To move the cursor left one word
  2033.  * Date:    June 5, 1991
  2034.  * Passed:  window:  pointer to current window
  2035.  * Notes:   Words are considered strings of letters, numbers and underscores,
  2036.  *          which must be separated by other characters.
  2037.  */
  2038. int  word_left( WINDOW *window )
  2039. {
  2040. text_ptr p;             /* text pointer */
  2041. int  len;               /* length of current line */
  2042. int  rc;
  2043. register int rcol;
  2044. long rline;
  2045. line_list_ptr ll;
  2046. WINDOW w;
  2047.  
  2048.    entab_linebuff( );
  2049.    if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  2050.       return( ERROR );
  2051.    rc = OK;
  2052.    dup_window_info( &w, window );
  2053.    rline = window->rline;
  2054.    rcol  = window->rcol;
  2055.    ll = window->ll;
  2056.    if (ll->len != EOF) {
  2057.       p = ll->line;
  2058.       len = ll->len;
  2059.  
  2060.       if (p != NULL  &&  rcol > 0  &&  rcol >= len  &&
  2061.                                       !myiswhitespc( *(p + len - 1) )) {
  2062.          rcol = len - 1;
  2063.          p += rcol;
  2064.          for (; rcol >= 0 && !myiswhitespc( *p ); rcol--, p--);
  2065.          ++rcol;
  2066.          check_virtual_col( window, rcol, rcol );
  2067.          make_ruler( window );
  2068.          show_ruler( window );
  2069.       } else {
  2070.          rcol = rcol >= len ? len-1 : rcol;
  2071.          if (rcol >= 0)
  2072.             p += rcol;
  2073.          if (p != NULL  &&  rcol > 0  &&  !myiswhitespc( *p )  &&
  2074.                                           !myiswhitespc( *(p-1) )) {
  2075.             for (; rcol >= 0 && !myiswhitespc( *p ); rcol--, p--);
  2076.             ++rcol;
  2077.             check_virtual_col( window, rcol, rcol );
  2078.             make_ruler( window );
  2079.             show_ruler( window );
  2080.          } else {
  2081.  
  2082.             /*
  2083.              * if we are on the first letter of a word, get off.
  2084.              */
  2085.             if (p != NULL)
  2086.                for (; rcol >= 0 && !myiswhitespc( *p ); rcol--, p--);
  2087.  
  2088.             /*
  2089.              * go to the next line if word begins at 1st col in line.
  2090.              */
  2091.             if (rcol < 0) {
  2092.                if (ll->prev != NULL) {
  2093.                   --rline;
  2094.                   ll = ll->prev;
  2095.                   p = ll->line;
  2096.                   rcol = ll->len - 1;
  2097.                   if (rcol >= 0)
  2098.                      p += rcol;
  2099.                } else
  2100.                   rc = ERROR;
  2101.             }
  2102.  
  2103.             /*
  2104.              * skip all blanks until we get to a previous word
  2105.              */
  2106.             while (rc == OK  &&  (p == NULL  ||  (p != NULL  &&
  2107.                                                   myiswhitespc( *p )))) {
  2108.                for (; rcol >= 0 && myiswhitespc( *p ); rcol--, p--);
  2109.                if (rcol < 0) {
  2110.                   if (ll->prev != NULL) {
  2111.                      --rline;
  2112.                      ll = ll->prev;
  2113.                      p = ll->line;
  2114.                      rcol = ll->len - 1;
  2115.                      if (rcol >= 0)
  2116.                         p += rcol;
  2117.                   } else
  2118.                      rc = ERROR;
  2119.                } else
  2120.                   break;
  2121.             }
  2122.  
  2123.             /*
  2124.              * now, find the beginning of the word.
  2125.              */
  2126.             if (rc == OK  &&  p != NULL) {
  2127.                for (; rcol >= 0 && !myiswhitespc( *p ); rcol--, p--);
  2128.                bin_offset_adjust( window, rline );
  2129.                find_adjust( window, ll, rline, rcol+1 );
  2130.                if (rline != w.rline && !window->file_info->dirty) {
  2131.                   update_line( &w );
  2132.                   show_curl_line( window );
  2133.                }
  2134.                make_ruler( window );
  2135.                show_ruler( window );
  2136.             } else
  2137.                rc = ERROR;
  2138.          }
  2139.       }
  2140.    } else
  2141.       rc = ERROR;
  2142.  
  2143.    sync( window );
  2144.    return( rc );
  2145. }
  2146.  
  2147.  
  2148. /*
  2149.  * Name:    word_right
  2150.  * Purpose: To move the cursor right one word
  2151.  * Date:    June 5, 1991
  2152.  * Passed:  window:  pointer to current window
  2153.  * Notes:   Words are considered strings of letters, numbers and underscores,
  2154.  *           which must be separated by other characters.
  2155.  */
  2156. int  word_right( WINDOW *window )
  2157. {
  2158. int  len;               /* length of current line */
  2159. text_ptr p;             /* text pointer */
  2160. int  rc;
  2161. WINDOW w;
  2162. register int rcol;
  2163. line_list_ptr ll;
  2164. long rline;
  2165.  
  2166.    entab_linebuff( );
  2167.    if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  2168.       return( ERROR );
  2169.    rc = OK;
  2170.    dup_window_info( &w, window );
  2171.    rline = window->rline;
  2172.    rcol  = window->rcol;
  2173.    ll = window->ll;
  2174.    if (ll->len != EOF) {
  2175.       p = ll->line;
  2176.       len = ll->len;
  2177.  
  2178.       /*
  2179.        * if rcol is past EOL, move it to EOL
  2180.        */
  2181.       rcol = rcol >= len ? len-1 : rcol;
  2182.       if (rcol >= 0)
  2183.          p += rcol;
  2184.  
  2185.       /*
  2186.        * if cursor is on a word, find end of word.
  2187.        */
  2188.       if (p != NULL)
  2189.          for (; rcol < len && !myiswhitespc( *p ); rcol++, p++);
  2190.       else
  2191.          rcol = len;
  2192.  
  2193.       /*
  2194.        * go to the next line if word ends at eol.
  2195.        */
  2196.       if (rcol == len) {
  2197.          ++rline;
  2198.          ll = ll->next;
  2199.          if (ll->len != EOF) {
  2200.             p = ll->line;
  2201.             len = ll->len;
  2202.             rcol = 0;
  2203.          } else
  2204.             rc = ERROR;
  2205.       }
  2206.  
  2207.       /*
  2208.        * now, go forward thru the file looking for the first letter of word.
  2209.        */
  2210.       while (rc == OK && (p == NULL  ||  (p != NULL && myiswhitespc( *p )))) {
  2211.          for (; rcol < len && myiswhitespc( *p ); rcol++, p++);
  2212.          if (rcol == len) {
  2213.             ++rline;
  2214.             ll = ll->next;
  2215.             if (ll->len != EOF) {
  2216.                p = ll->line;
  2217.                len = ll->len;
  2218.                rcol = 0;
  2219.             } else
  2220.                rc = ERROR;
  2221.          } else
  2222.             break;
  2223.       }
  2224.    } else
  2225.       rc = ERROR;
  2226.  
  2227.    if (rc == OK) {
  2228.       bin_offset_adjust( window, rline );
  2229.       find_adjust( window, ll, rline, rcol );
  2230.       make_ruler( window );
  2231.       show_ruler( window );
  2232.    }
  2233.  
  2234.    if (rline != w.rline && !window->file_info->dirty) {
  2235.       update_line( &w );
  2236.       show_curl_line( window );
  2237.    }
  2238.    sync( window );
  2239.    return( rc );
  2240. }
  2241.  
  2242.  
  2243. /*
  2244.  * Name:    next_dirty_line
  2245.  * Purpose: To move the cursor to the next dirty line, if it exists
  2246.  * Date:    April 1, 1993
  2247.  * Passed:  window:  pointer to current window
  2248.  */
  2249. int  next_dirty_line( WINDOW *window )
  2250. {
  2251. int  rc;
  2252. line_list_ptr ll;
  2253. long rline;
  2254. long bin_offset;       /* binary offset */
  2255. WINDOW w;
  2256.  
  2257.    entab_linebuff( );
  2258.    if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  2259.       return( ERROR );
  2260.    rc = OK;
  2261.    dup_window_info( &w, window );
  2262.    rline = window->rline;
  2263.    ll = window->ll;
  2264.    bin_offset = window->bin_offset;
  2265.    if (ll->len != EOF) {
  2266.       while (rc == OK) {
  2267.          if (ll->len != EOF) {
  2268.             ++rline;
  2269.             bin_offset += ll->len;
  2270.             ll = ll->next;
  2271.             if (ll->dirty == TRUE)
  2272.                break;
  2273.          } else
  2274.             rc = ERROR;
  2275.       }
  2276.    } else
  2277.       rc = ERROR;
  2278.  
  2279.    if (rc == OK) {
  2280.       window->bin_offset = bin_offset;
  2281.       find_adjust( window, ll, rline, window->rcol );
  2282.       make_ruler( window );
  2283.       show_ruler( window );
  2284.    } else
  2285.       error( WARNING, window->bottom_line, utils16 );
  2286.  
  2287.    if (rline != w.rline && !window->file_info->dirty) {
  2288.       update_line( &w );
  2289.       show_curl_line( window );
  2290.    }
  2291.    sync( window );
  2292.    return( rc );
  2293. }
  2294.  
  2295.  
  2296. /*
  2297.  * Name:    prev_dirty_line
  2298.  * Purpose: To move the cursor to the prev dirty line, if it exists
  2299.  * Date:    April 1, 1993
  2300.  * Passed:  window:  pointer to current window
  2301.  */
  2302. int  prev_dirty_line( WINDOW *window )
  2303. {
  2304. int  rc;
  2305. line_list_ptr ll;
  2306. long rline;
  2307. long bin_offset;        /* binary offset */
  2308. WINDOW w;
  2309.  
  2310.    entab_linebuff( );
  2311.    if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  2312.       return( ERROR );
  2313.    rc = OK;
  2314.    dup_window_info( &w, window );
  2315.    rline = window->rline;
  2316.    ll = window->ll;
  2317.    bin_offset = window->bin_offset;
  2318.    if (ll->prev != NULL) {
  2319.       while (rc == OK) {
  2320.          if (ll->prev != NULL) {
  2321.             --rline;
  2322.             ll = ll->prev;
  2323.             bin_offset -= ll->len;
  2324.             if (ll->dirty == TRUE)
  2325.                break;
  2326.          } else
  2327.             rc = ERROR;
  2328.       }
  2329.    } else
  2330.       rc = ERROR;
  2331.  
  2332.    if (rc == OK) {
  2333.       window->bin_offset = bin_offset;
  2334.       find_adjust( window, ll, rline, window->rcol );
  2335.       make_ruler( window );
  2336.       show_ruler( window );
  2337.    } else
  2338.       error( WARNING, window->bottom_line, utils16 );
  2339.  
  2340.    if (rline != w.rline && !window->file_info->dirty) {
  2341.       update_line( &w );
  2342.       show_curl_line( window );
  2343.    }
  2344.    sync( window );
  2345.    return( rc );
  2346. }
  2347.  
  2348.  
  2349. /*
  2350.  * Name:    center_window
  2351.  * Purpose: To place the current line or cursor in the center of a window.
  2352.  * Date:    June 5, 1991
  2353.  * Passed:  window:  pointer to current window
  2354.  */
  2355. int  center_window( WINDOW *window )
  2356. {
  2357. int  center;
  2358. int  center_line;
  2359. int  diff;
  2360. register file_infos *file;
  2361. register WINDOW *win;           /* put window pointer in a register */
  2362.  
  2363.    win = window;
  2364.    file = win->file_info;
  2365.    center = (win->bottom_line + 1 - win->top_line) / 2 - win->ruler;
  2366.    center_line = win->top_line + win->ruler + center;
  2367.    diff = center_line - win->cline;
  2368.    entab_linebuff( );
  2369.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  2370.       return( ERROR );
  2371.    if (g_status.command == CenterWindow) {
  2372.       if (diff > 0) {
  2373.          if (win->rline + diff <= file->length) {
  2374.             update_line( win );
  2375.             win->cline += diff;
  2376.             win->rline += diff;
  2377.             for (; diff > 0; diff--) {
  2378.                win->bin_offset += win->ll->len;
  2379.                win->ll = win->ll->next;
  2380.             }
  2381.             show_curl_line( win );
  2382.          }
  2383.       } else if (diff < 0) {
  2384.          update_line( win );
  2385.          win->cline += diff;
  2386.          win->rline += diff;
  2387.          for (; diff < 0; diff++) {
  2388.             win->ll = win->ll->prev;
  2389.             win->bin_offset -= win->ll->len;
  2390.          }
  2391.          show_curl_line( win );
  2392.       }
  2393.    } else {
  2394.       if (diff > 0) {
  2395.          win->cline += diff;
  2396.          if ((long)(win->cline+1 - (win->top_line + win->ruler)) > win->rline)
  2397.             win->cline = (win->top_line + win->ruler) - 1 + (int)win->rline;
  2398.          file->dirty = LOCAL;
  2399.       } else if (diff < 0) {
  2400.          win->cline = win->cline + diff;
  2401.          file->dirty = LOCAL;
  2402.       }
  2403.    }
  2404.    if (g_status.command == CenterWindow  ||  g_status.command == CenterLine)
  2405.       sync( win );
  2406.    return( OK );
  2407. }
  2408.  
  2409.  
  2410. /*
  2411.  * Name:    horizontal_screen_right
  2412.  * Purpose: To move the cursor one screen to the right
  2413.  * Date:    September 13, 1991
  2414.  * Passed:  window:  pointer to current window
  2415.  * Notes:   Add 80 columns to the real cursor.  If the cursor is past the
  2416.  *          maximum line length then move it back.
  2417.  */
  2418. int  horizontal_screen_right( WINDOW *window )
  2419. {
  2420. int  col;
  2421.  
  2422.    col = window->rcol;
  2423.    col += (window->end_col + 1 - window->start_col);
  2424.    if (col < MAX_LINE_LENGTH) {
  2425.       window->rcol = col;
  2426.       window->bcol += (window->end_col + 1 - window->start_col);
  2427.       window->file_info->dirty = LOCAL;
  2428.       check_virtual_col( window, window->rcol, window->ccol );
  2429.       make_ruler( window );
  2430.       show_ruler( window );
  2431.    }
  2432.    sync( window );
  2433.    return( OK );
  2434. }
  2435.  
  2436.  
  2437. /*
  2438.  * Name:    horizontal_screen_left
  2439.  * Purpose: To move the cursor one screen to the left
  2440.  * Date:    September 13, 1991
  2441.  * Passed:  window:  pointer to current window
  2442.  * Notes:   Subtract screen width from the real cursor.  If the cursor is less
  2443.  *           than zero then see if bcol is zero.  If bcol is not zero then make
  2444.  *           bcol zero.
  2445.  */
  2446. int  horizontal_screen_left( WINDOW *window )
  2447. {
  2448. int  screen_width;
  2449.  
  2450.    screen_width = window->end_col + 1 - window->start_col;
  2451.    if (window->rcol - screen_width < 0) {
  2452.       if (window->bcol != 0) {
  2453.          window->bcol = 0;
  2454.          window->file_info->dirty = LOCAL;
  2455.       }
  2456.    } else {
  2457.       window->rcol -= screen_width;
  2458.       window->bcol -= screen_width;
  2459.       if (window->bcol < 0)
  2460.          window->bcol = 0;
  2461.       window->file_info->dirty = LOCAL;
  2462.    }
  2463.    check_virtual_col( window, window->rcol, window->ccol );
  2464.    sync( window );
  2465.    make_ruler( window );
  2466.    show_ruler( window );
  2467.    return( OK );
  2468. }
  2469.  
  2470.  
  2471. /*
  2472.  * Name:    goto_top_file
  2473.  * Purpose: To move the cursor to the top of the file.
  2474.  * Date:    June 5, 1991
  2475.  * Passed:  window:  pointer to current window
  2476.  */
  2477. int  goto_top_file( WINDOW *window )
  2478. {
  2479. register WINDOW *win;   /* put window pointer in a register */
  2480. long num;
  2481.  
  2482.    win = window;
  2483.    entab_linebuff( );
  2484.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  2485.       return( ERROR );
  2486.    if (win->rline != win->cline - (win->top_line+win->ruler-1)) {
  2487.       win->bin_offset = 0;
  2488.       win->rline = win->cline - (win->top_line+win->ruler-1);
  2489.       win->ll = win->file_info->line_list;
  2490.       for (num=1; num < win->rline; num++) {
  2491.          win->bin_offset += win->ll->len;
  2492.          win->ll = win->ll->next;
  2493.       }
  2494.       display_current_window( win );
  2495.    }
  2496.    sync( win );
  2497.    return( OK );
  2498. }
  2499.  
  2500.  
  2501. /*
  2502.  * Name:    goto_end_file
  2503.  * Purpose: To move the cursor to the end of the file.
  2504.  * Date:    June 5, 1991
  2505.  * Passed:  window:  pointer to current window
  2506.  */
  2507. int  goto_end_file( WINDOW *window )
  2508. {
  2509. register WINDOW *win;  /* put window pointer in a register */
  2510. line_list_ptr ll;
  2511. long length;
  2512.  
  2513.    win = window;
  2514.    entab_linebuff( );
  2515.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  2516.       return( ERROR );
  2517.    length = win->file_info->length;
  2518.    if (length > win->rline + win->bottom_line - win->cline) {
  2519.       win->rline = length - (win->bottom_line - win->cline) + 1;
  2520.       win->ll = win->file_info->line_list_end;
  2521.       for (;length >= win->rline; length--)
  2522.          win->ll = win->ll->prev;
  2523.  
  2524.       win->bin_offset = 0;
  2525.       ll = win->file_info->line_list;
  2526.       for (length = 1; length < win->rline; length++) {
  2527.          win->bin_offset += ll->len;
  2528.          ll = ll->next;
  2529.       }
  2530.  
  2531.       display_current_window( win );
  2532.    }
  2533.    sync( win );
  2534.    return( OK );
  2535. }
  2536.  
  2537.  
  2538. /*
  2539.  * Name:    goto_line
  2540.  * Purpose: To move the cursor to a particular line in the file
  2541.  * Date:    June 5, 1991
  2542.  * Passed:  window:  pointer to current window
  2543.  */
  2544. int  goto_line( WINDOW *window )
  2545. {
  2546. long number;            /* line number selected */
  2547. long n;
  2548. char num_str[MAX_COLS]; /* line number as string */
  2549. register WINDOW *win;   /* put window pointer in a register */
  2550. line_list_ptr ll;
  2551. int  rc;
  2552.  
  2553.    win = window;
  2554.    entab_linebuff( );
  2555.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  2556.       return( ERROR );
  2557.    /*
  2558.     * find out where we are going
  2559.     */
  2560.    num_str[0] = '\0';
  2561.    /*
  2562.     * line number:
  2563.     */
  2564.    if (get_name( find11, win->bottom_line, num_str,
  2565.                  g_display.message_color ) != OK  ||  *num_str == '\0')
  2566.       return( ERROR );
  2567.    number = atol( num_str );
  2568.  
  2569.    if (number > 0  && number <= (long)win->file_info->length) {
  2570.       update_line( win );
  2571.       ll = win->ll;
  2572.       n = win->rline;
  2573.       if (number < win->rline) {
  2574.          if (n - number < number - 1) {
  2575.             for (; n > number; n--) {
  2576.                ll = ll->prev;
  2577.                win->bin_offset -= ll->len;
  2578.             }
  2579.          } else {
  2580.             ll = win->file_info->line_list;
  2581.             n = 1;
  2582.             for (; n < number; n++) {
  2583.                win->bin_offset += ll->len;
  2584.                ll = ll->next;
  2585.             }
  2586.          }
  2587.       } else if (number > win->rline) {
  2588.          for (; n < number; n++) {
  2589.             win->bin_offset += ll->len;
  2590.             ll = ll->next;
  2591.          }
  2592.       }
  2593.       find_adjust( win, ll, number, win->rcol );
  2594.       if (!win->file_info->dirty)
  2595.          show_curl_line( win );
  2596.       rc = OK;
  2597.    } else {
  2598.       /*
  2599.        * out of range.  must be in the range 1 -
  2600.        */
  2601.       strcat( num_str, find12 );
  2602.       ltoa( win->file_info->length, num_str+25, 10 );
  2603.       error( WARNING, win->bottom_line, num_str );
  2604.       rc = ERROR;
  2605.    }
  2606.    return( rc );
  2607. }
  2608.  
  2609.  
  2610. /*
  2611.  * Name:    set_marker
  2612.  * Purpose: To set file marker
  2613.  * Date:    December 28, 1991
  2614.  * Passed:  window:  pointer to current window
  2615.  */
  2616. int  set_marker( WINDOW *window )
  2617. {
  2618. register MARKER  *marker;       /* put the marker in a register */
  2619.  
  2620.    marker = &window->file_info->marker[g_status.command - SetMark1];
  2621.    marker->rline  = window->rline;
  2622.    marker->rcol   = window->rcol;
  2623.    marker->ccol   = window->ccol;
  2624.    marker->bcol   = window->bcol;
  2625.    marker->marked = TRUE;
  2626.    return( OK );
  2627. }
  2628.  
  2629.  
  2630. /*
  2631.  * Name:    goto_marker
  2632.  * Purpose: To goto a file marker
  2633.  * Date:    December 28, 1991
  2634.  * Passed:  window:  pointer to current window
  2635.  */
  2636. int  goto_marker( WINDOW *window )
  2637. {
  2638. int  m;
  2639. file_infos *file;
  2640. long new_rline;
  2641. long n;
  2642. MARKER *marker;
  2643. register WINDOW *win;   /* put window pointer in a register */
  2644. line_list_ptr ll;
  2645. int  rc;
  2646.  
  2647.    win = window;
  2648.    m = g_status.command - GotoMark1;
  2649.    file = win->file_info;
  2650.    marker = &file->marker[m];
  2651.    if (marker->marked) {
  2652.       entab_linebuff( );
  2653.       if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  2654.          return( ERROR );
  2655.       file->dirty = LOCAL;
  2656.       if (marker->rline > file->length)
  2657.          marker->rline = file->length;
  2658.       if (marker->rline < 1l)
  2659.          marker->rline = 1l;
  2660.       new_rline = marker->rline;
  2661.       ll = win->ll;
  2662.       if (new_rline < win->rline) {
  2663.          if (win->rline - new_rline < new_rline - 1) {
  2664.             for (n=win->rline; n > new_rline; n--) {
  2665.                ll = ll->prev;
  2666.                win->bin_offset -= ll->len;
  2667.             }
  2668.          } else {
  2669.             ll = win->file_info->line_list;
  2670.             win->bin_offset = 0;
  2671.             n = 1;
  2672.             for (; n < new_rline; n++) {
  2673.                win->bin_offset += ll->len;
  2674.                ll = ll->next;
  2675.             }
  2676.          }
  2677.       } else if (new_rline > win->rline) {
  2678.          n = win->rline;
  2679.          for (; n < new_rline; n++) {
  2680.             win->bin_offset += ll->len;
  2681.             ll = ll->next;
  2682.          }
  2683.       }
  2684.       win->rline  = new_rline;
  2685.       win->ll     = ll;
  2686.       win->rcol   = marker->rcol;
  2687.       win->ccol   = marker->ccol;
  2688.       win->bcol   = marker->bcol;
  2689.       if (win->rline < (win->cline - ((win->top_line + win->ruler) - 1)))
  2690.          win->cline = (int)win->rline + (win->top_line + win->ruler) - 1;
  2691.       check_virtual_col( win, win->rcol, win->ccol );
  2692.       make_ruler( window );
  2693.       show_ruler( window );
  2694.       rc = OK;
  2695.    } else {
  2696.       if (m == 9)
  2697.          m = -1;
  2698.       *(utils13 + 7) = (char)('0' + m + 1);
  2699.       /*
  2700.        * marker not set
  2701.        */
  2702.       error( WARNING, win->bottom_line, utils13 );
  2703.       rc = ERROR;
  2704.    }
  2705.    return( rc );
  2706. }
  2707.  
  2708.  
  2709. /*
  2710.  * Name:    date_time_stamp
  2711.  * Purpose: put system date and time into file at cursor position
  2712.  * Date:    June 5, 1992
  2713.  * Passed:  window:  pointer to current window
  2714.  */
  2715. int  date_time_stamp( WINDOW *window )
  2716. {
  2717. char date_time[MAX_COLS];
  2718. char stuff[20];
  2719. register char *dt;
  2720. int  year, month, day;
  2721. int  hours, minutes;
  2722. int  one, two, three;
  2723. int  i;
  2724. int  pm;
  2725.  
  2726.  
  2727.    get_date( &year, &month, &day, &i );
  2728.    get_time( &hours, &minutes, &i, &i );
  2729.    dt = date_time;
  2730.  
  2731.    /*
  2732.     * mod year with 100 if needed.
  2733.     */
  2734.    switch (mode.date_style) {
  2735.       case MM_DD_YY  :
  2736.       case DD_MM_YY  :
  2737.       case YY_MM_DD  :
  2738.          year = year % 100;
  2739.    }
  2740.  
  2741.    switch (mode.date_style) {
  2742.       case DD_MM_YY   :
  2743.       case DD_MM_YYYY :
  2744.          one = day;
  2745.          two = month;
  2746.          three = year;
  2747.          break;
  2748.       case YY_MM_DD   :
  2749.       case YYYY_MM_DD :
  2750.          one = year;
  2751.          two = month;
  2752.          three = day;
  2753.          break;
  2754.       case MM_DD_YY   :
  2755.       case MM_DD_YYYY :
  2756.       default         :
  2757.          one = month;
  2758.          two = day;
  2759.          three = year;
  2760.          break;
  2761.    }
  2762.    strcpy( dt, itoa( one, stuff, 10 ) );
  2763.    strcat( dt, "-" );
  2764.    strcat( dt, itoa( two, stuff, 10 ) );
  2765.    strcat( dt, "-" );
  2766.    strcat( dt, itoa( three, stuff, 10 ) );
  2767.  
  2768.    strcat( dt, "  " );
  2769.  
  2770.    pm = FALSE;
  2771.    if (mode.time_style == _12_HOUR) {
  2772.       if (hours >= 12 && hours < 24)
  2773.          pm = TRUE;
  2774.       if (hours < 1)
  2775.          hours = 12;
  2776.       else if (hours >= 13)
  2777.          hours -= 12;
  2778.    }
  2779.  
  2780.    if (hours < 1)
  2781.       strcat( dt, "0" );
  2782.    strcat( dt, itoa( hours, stuff, 10 ) );
  2783.    strcat( dt, ":" );
  2784.    if (minutes < 10)
  2785.       strcat( dt, "0" );
  2786.    strcat( dt, itoa( minutes, stuff, 10 ) );
  2787.    if (mode.time_style == _12_HOUR)
  2788.       strcat( dt, pm == FALSE ? "am" : "pm" );
  2789.    strcat( dt, "  " );
  2790.    return( add_chars( dt, window ) );
  2791. }
  2792.  
  2793.  
  2794. /*
  2795.  * Name:    add_chars
  2796.  * Purpose: insert string into file
  2797.  * Date:    June 5, 1992
  2798.  * Passed:  string:  string to add to file
  2799.  *          window:  pointer to current window
  2800.  */
  2801. int  add_chars( char *string, WINDOW *window )
  2802. {
  2803. int  rc = OK;
  2804.  
  2805.    while (*string) {
  2806.       g_status.key_pressed = *string;
  2807.       rc = insert_overwrite( window );
  2808.       ++string;
  2809.    }
  2810.    return( rc );
  2811. }
  2812.